#include "Vector.h"
#include <math.h>


#pragma region vector2
	Vector2::Vector2()
	{
		X = 0;
		Y = 0;
	}
	Vector2::Vector2(int v)
	{
		X = (float)v;
		Y = (float)v;
	}
	Vector2::Vector2(float v)
	{
		X = v;
		Y = v;
	}
	Vector2::Vector2(int x,int y)
	{
		X = (float)x;
		Y = (float)y;
	}
	Vector2::Vector2(float x,float y)
	{
		X = x;
		Y = y;
	}
	float Vector2::Length()
	{
		return sqrt((X*X) + (Y*Y));
	}
	float Vector2::LengthSquared()
	{
		return (X*X) + (Y*Y);
	}
	float Vector2::Dot(Vector2 vecA,Vector2 vecB)
	{
		return (vecA.X*vecB.X)+(vecA.Y*vecB.Y);
	}
	Vector2 Vector2::Lerp(Vector2 vecA,Vector2 vecB,float value)
	{
		Vector2 vecC = vecB - vecA;
		return (vecC * value)+vecA;
	}	
	Vector2 Vector2::operator+ (Vector2 vec)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X += vec.X;
		tempVec.Y += vec.Y;
		return tempVec;
		
	}
	Vector2 Vector2::operator- (Vector2 vec)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X -= vec.X;
		tempVec.Y -= vec.Y;
		return tempVec;
	}
	Vector2 Vector2::operator* (Vector2 vec)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X *= vec.X;
		tempVec.Y *= vec.Y;
		return tempVec;
	}
	Vector2 Vector2::operator/ (Vector2 vec)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X /= vec.X;
		tempVec.Y /= vec.Y;
		return tempVec;
	}
	Vector2 Vector2::operator* (float value)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X *= value;
		tempVec.Y *= value;
		return tempVec;
	}
	Vector2 Vector2::operator/ (float value)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X /= value;
		tempVec.Y /= value;
		return tempVec;
	}
	Vector2 Vector2::operator* (int value)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X *= value;
		tempVec.Y *= value;
		return tempVec;
	}
	Vector2 Vector2::operator/ (int value)
	{
		Vector2 tempVec = Vector2(X,Y);
		tempVec.X /= value;
		tempVec.Y /= value;
		return tempVec;
	}
	Vector2 Vector2::Normalize(Vector2 vec)
	{
		return vec / vec.Length();
	}
	Vector2 Vector2::CircleToCartesian(float angle,float distance)
	{
		Vector2 tempVec;
		tempVec.X = sin(angle);
		tempVec.Y = cos(angle);
		tempVec = tempVec * distance;
		return tempVec;
	}
	Vector2 Vector2::Clamp(Vector2 vec,Vector2 max,Vector2 min)
	{
		Vector2 tempVec = vec;
		if(vec.X < min.X){tempVec.X = min.X;}
		if(vec.X < min.Y){tempVec.Y = min.Y;}
		if(vec.X > max.X){tempVec.X = max.X;}
		if(vec.Y > max.Y){tempVec.Y = max.Y;}
		return tempVec;
	}
	Vector2 Vector2::One = Vector2(1,1);
	Vector2 Vector2::Zero = Vector2(0,0);
	Vector2 Vector2::UnitX = Vector2(1,0);
	Vector2 Vector2::UnitY = Vector2(0,1);

#pragma endregion vector2

#pragma region vector3
	Vector3::Vector3()
	{
		X = 0;
		Y = 0;
		Z = 0;
	}
	Vector3::Vector3(int v)
	{
		X = (float)v;
		Y = (float)v;
		Z = (float)v;
	}
	Vector3::Vector3(float v)
	{
		X = v;
		Y = v;
		Z = v;
	}
	Vector3::Vector3(int x,int y,int z)
	{
		X = (float)x;
		Y = (float)y;
		Z = (float)z;
	}
	Vector3::Vector3(float x,float y,float z)
	{
		X = x;
		Y = y;
		Z = z;
	}
	Vector3::Vector3(Vector2 vec2,float z)
	{
		X = vec2.X;
		Y = vec2.Y;
		Z = z;
	}
	float Vector3::Length()
	{
		return sqrt((X*X) + (Y*Y)+ (Z*Z));
	}
	float Vector3::LengthSquared()
	{
		return (X*X) + (Y*Y) + (Z*Z);
	}
	float Vector3::Dot(Vector3 vecA,Vector3 vecB)
	{
		return 
			(vecA.X*vecB.X)+
			(vecA.Y*vecB.Y)+
			(vecA.Z*vecB.Z);
	}
	Vector3 Vector3::Cross(Vector3 vecA,Vector3 vecB)
	{
		Vector3 cross;
		cross.X = vecA.Y * vecB.Z - vecA.Z * vecB.Y;
		cross.Y = vecA.Z * vecB.X - vecA.X * vecB.Z;
		cross.Z = vecA.X * vecB.Y - vecA.Y * vecB.X;
		return cross;
	}
	Vector3 Vector3::Lerp(Vector3 vecA,Vector3 vecB,float value)
	{
		Vector3 vecC = vecB - vecA;
		return (vecC * value)+vecA;
	}	
	Vector3 Vector3::Transform(Vector3 vec, Matrix matrix)
	{
		Vector3 newVec;
		newVec.X = matrix.M[0][0] * vec.X;
		newVec.X += matrix.M[0][1] * vec.Y;
		newVec.X += matrix.M[0][2] * vec.Z;

		newVec.Y = matrix.M[1][0] * vec.X;
		newVec.Y += matrix.M[1][1] * vec.Y;
		newVec.Y += matrix.M[1][2] * vec.Z;

		newVec.Z = matrix.M[2][0] * vec.X;
		newVec.Z += matrix.M[2][1] * vec.Y;
		newVec.Z += matrix.M[2][2] * vec.Z;
		return newVec;
	}	
	Vector3 Vector3::operator+ (Vector3 vec)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X += vec.X;
		tempVec.Y += vec.Y;
		tempVec.Z += vec.Z;
		return tempVec;
		
	}
	Vector3 Vector3::operator- (Vector3 vec)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X -= vec.X;
		tempVec.Y -= vec.Y;
		tempVec.Z -= vec.Z;
		return tempVec;
	}
	Vector3 Vector3::operator* (Vector3 vec)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X *= vec.X;
		tempVec.Y *= vec.Y;
		tempVec.Z *= vec.Z;
		return tempVec;
	}
	Vector3 Vector3::operator/ (Vector3 vec)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X /= vec.X;
		tempVec.Y /= vec.Y;
		tempVec.Z /= vec.Z;
		return tempVec;
	}
	Vector3 Vector3::operator* (float value)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X *= value;
		tempVec.Y *= value;
		tempVec.Z *= value;
		return tempVec;
	}
	Vector3 Vector3::operator/ (float value)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X /= value;
		tempVec.Y /= value;
		tempVec.Z /= value;
		return tempVec;
	}
	Vector3 Vector3::operator* (int value)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X *= value;
		tempVec.Y *= value;
		tempVec.Z *= value;
		return tempVec;
	}
	Vector3 Vector3::operator/ (int value)
	{
		Vector3 tempVec = Vector3(X,Y,Z);
		tempVec.X /= value;
		tempVec.Y /= value;
		tempVec.Z /= value;
		return tempVec;
	}
	Vector3 Vector3::Normalize(Vector3 vec)
	{
		return vec / vec.Length();
	}
	Vector3 Vector3::SphereToCartesian(float angleA,float angleB,float distance)
	{
		Vector3 tempVec;
		tempVec.X = sin(angleA);
		tempVec.Z = cos(angleA);
		tempVec = tempVec * sin(angleB);
		tempVec.Y = cos(angleB);
		tempVec = tempVec * distance;
		return tempVec;
	}
	Vector3 Vector3::Clamp(Vector3 vec,Vector3 max,Vector3 min)
	{
		Vector3 tempVec = vec;
		if(vec.X < min.X){tempVec.X = min.X;}
		if(vec.Y < min.Y){tempVec.Y = min.Y;}
		if(vec.Z < min.Z){tempVec.Z = min.Z;}

		if(vec.X > max.X){tempVec.X = max.X;}
		if(vec.Y > max.Y){tempVec.Y = max.Y;}
		if(vec.Z > max.Z){tempVec.Z = max.Z;}
		return tempVec;
	}
	Vector3 Vector3::One = Vector3(1,1,1);
	Vector3 Vector3::Zero = Vector3(0,0,0);		
	Vector3 Vector3::Left = Vector3(1,0,0);	
	Vector3 Vector3::Right = Vector3(-1,0,0);
	Vector3 Vector3::Up = Vector3(0,1,0);	
	Vector3 Vector3::Down = Vector3(0,-1,0);	
	Vector3 Vector3::Forward = Vector3(0,0,1);	
	Vector3 Vector3::Backward = Vector3(0,0,-1);	

#pragma endregion vector3